﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Sustainalytics.ClientDW.Entities.Universes;
using Sustainalytics.ClientDW.Entities;
using System.Linq;

namespace Sustainalytics.Universes.Synchronization.Tests
{
    [TestClass]
    public class UniverseResearchCoverageTest
    {
        [TestInitialize]
        public void TestInit()
        {

        }

        [TestMethod]
        public void TestResearchCoverage3()
        {
            Guid cocaColaCompanyId = Guid.NewGuid();
            Guid cocaColaAmatilId = Guid.NewGuid();
            Guid cocaColaBottlingId = Guid.NewGuid();
            Guid cocaColaJapanId = Guid.NewGuid();
            Guid accountId1 = Guid.NewGuid();
            Guid accountId2 = Guid.NewGuid();
            int cocaColaCompanyCIQID = 1000;
            int cocaColaAmatilCIQID = 1001;
            int cocaColaBottlingCIQID = 1002;
            int cocaColaJapanCIQID = 1003;

            var universes = new List<Tuple<int, Guid>>
            {
                 new Tuple<int, Guid>(201, accountId1),
                 new Tuple<int, Guid>(202, accountId1),
                 new Tuple<int, Guid>(203, accountId2),
                 new Tuple<int, Guid>(204, accountId2),
            };

            var univCompanies = new List<UniverseCompany>();
            foreach (var univ in universes)
            {
                univCompanies.Add(new UniverseCompany() { CompanyId = cocaColaCompanyId, UniverseId = univ.Item1, AccountId = univ.Item2 });
            };

            var corporateData2 = FillCorporateData3(new List<Tuple<Guid, int>>
            {
                new Tuple<Guid, int>(cocaColaCompanyId, cocaColaCompanyCIQID),
                new Tuple<Guid, int>(cocaColaAmatilId, cocaColaAmatilCIQID),
                new Tuple<Guid, int>(cocaColaBottlingId, cocaColaBottlingCIQID),
                new Tuple<Guid, int>(cocaColaJapanId, cocaColaJapanCIQID),
            });

            var univCompaniesResult = new UniverseResearchCoverage().ProcessCoverage(univCompanies, corporateData2).ToList();

            Assert.AreEqual(univCompaniesResult.Count, 4);

            List<Tuple<int, Guid>> cocaColaCompanyUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaAmatilUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaBottlingUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaJapanUniverses = new List<Tuple<int, Guid>>();

            FillUniverses(cocaColaCompanyId, cocaColaAmatilId, cocaColaBottlingId, cocaColaJapanId, univCompaniesResult,
                cocaColaCompanyCIQID, cocaColaAmatilCIQID, cocaColaBottlingCIQID, cocaColaJapanCIQID,
                cocaColaCompanyUniverses, cocaColaAmatilUniverses, cocaColaBottlingUniverses, cocaColaJapanUniverses);

            CheckUniversesForCompany(cocaColaCompanyUniverses, universes);
            CheckUniversesForCompany(cocaColaAmatilUniverses, new List<Tuple<int, Guid>>());
            CheckUniversesForCompany(cocaColaBottlingUniverses, new List<Tuple<int, Guid>>());
            CheckUniversesForCompany(cocaColaJapanUniverses, new List<Tuple<int, Guid>>());
        }

        [TestMethod]
        public void TestResearchCoverage2()
        {
            Guid cocaColaCompanyId = Guid.NewGuid();
            Guid cocaColaAmatilId = Guid.NewGuid();
            Guid cocaColaBottlingId = Guid.NewGuid();
            Guid cocaColaJapanId = Guid.NewGuid();
            Guid accountId1 = Guid.NewGuid();
            Guid accountId2 = Guid.NewGuid();
            int cocaColaCompanyCIQID = 1000;
            int cocaColaAmatilCIQID = 1001;
            int cocaColaBottlingCIQID =1002;
            int cocaColaJapanCIQID = 1003;

            var universes = new List<Tuple<int, Guid>>
            {
                 new Tuple<int, Guid>(201, accountId1),
                 new Tuple<int, Guid>(202, accountId1),
                 new Tuple<int, Guid>(203, accountId2),
                 new Tuple<int, Guid>(204, accountId2),
            };

            var univCompanies = new List<UniverseCompany>();
            foreach(var univ in universes)
            {
                univCompanies.Add(new UniverseCompany(){CompanyId=cocaColaCompanyId, UniverseId = univ.Item1, AccountId=univ.Item2});
            };

            var corporateData2 = FillCorporateData2(cocaColaCompanyId, cocaColaAmatilId, cocaColaBottlingId, cocaColaJapanId,
                cocaColaCompanyCIQID, cocaColaAmatilCIQID, cocaColaBottlingCIQID, cocaColaJapanCIQID);

            var univCompaniesResult = new UniverseResearchCoverage().ProcessCoverage(univCompanies, corporateData2).ToList();

            Assert.AreEqual(univCompaniesResult.Count, univCompanies.Count*4);

            List<Tuple<int, Guid>> cocaColaCompanyUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaAmatilUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaBottlingUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaJapanUniverses = new List<Tuple<int, Guid>>();

            FillUniverses(cocaColaCompanyId, cocaColaAmatilId, cocaColaBottlingId, cocaColaJapanId, univCompaniesResult, 
                cocaColaCompanyCIQID, cocaColaAmatilCIQID, cocaColaBottlingCIQID, cocaColaJapanCIQID,
                cocaColaCompanyUniverses, cocaColaAmatilUniverses, cocaColaBottlingUniverses, cocaColaJapanUniverses);

            CheckUniversesForCompany(cocaColaCompanyUniverses, universes);
            CheckUniversesForCompany(cocaColaAmatilUniverses, universes);
            CheckUniversesForCompany(cocaColaBottlingUniverses, universes);
            CheckUniversesForCompany(cocaColaJapanUniverses, universes);
        }

        private static void FillUniverses(Guid cocaColaCompanyId, Guid cocaColaAmatilId, Guid cocaColaBottlingId, Guid cocaColaJapanId, 
            List<UniverseCompany> univCompaniesResult,
            int cocaColaCompanyCIQID, int cocaColaAmatilCIQID, int cocaColaBottlingCIQID, int cocaColaJapanCIQID,
            List<Tuple<int, Guid>> cocaColaCompanyUniverses, List<Tuple<int, Guid>> cocaColaAmatilUniverses, List<Tuple<int, Guid>> cocaColaBottlingUniverses, List<Tuple<int, Guid>> cocaColaJapanUniverses)
        {
            foreach (var uc in univCompaniesResult)
            {
                if (uc.CompanyId == cocaColaCompanyId)
                {
                    cocaColaCompanyUniverses.Add(new Tuple<int,Guid>(uc.UniverseId, uc.AccountId));
                    Assert.AreEqual(uc.CIQID, cocaColaCompanyCIQID.ToString());
                }
                else if (uc.CompanyId == cocaColaAmatilId)
                {
                    cocaColaAmatilUniverses.Add(new Tuple<int,Guid>(uc.UniverseId, uc.AccountId));
                    Assert.AreEqual(uc.CIQID, cocaColaAmatilCIQID.ToString());
                }
                else if (uc.CompanyId == cocaColaBottlingId)
                {
                    cocaColaBottlingUniverses.Add(new Tuple<int,Guid>(uc.UniverseId, uc.AccountId));
                    Assert.AreEqual(uc.CIQID, cocaColaBottlingCIQID.ToString());
                }
                else if (uc.CompanyId == cocaColaJapanId)
                {
                    cocaColaJapanUniverses.Add(new Tuple<int, Guid>(uc.UniverseId, uc.AccountId));
                    Assert.AreEqual(uc.CIQID, cocaColaJapanCIQID.ToString());
                }
            }
        }

        [TestMethod]
        public void TestResearchCoverage()
        {
            Guid cocaColaCompanyId = Guid.NewGuid();
            Guid cocaColaAmatilId = Guid.NewGuid();
            Guid cocaColaBottlingId = Guid.NewGuid();
            Guid cocaColaJapanId = Guid.NewGuid();
            Guid accountId1 = Guid.NewGuid();
            Guid accountId2 = Guid.NewGuid();
            Guid accountId3 = Guid.NewGuid();
            Guid accountId4 = Guid.NewGuid();
            int cocaColaCompanyCIQID = 1000;
            int cocaColaAmatilCIQID = 1001;
            int cocaColaBottlingCIQID = 1002;
            int cocaColaJapanCIQID = 1003;

            var universes = new List<Tuple<int, Guid>>
            {
                 new Tuple<int, Guid>(201, accountId1),
                 new Tuple<int, Guid>(202, accountId1),
                 new Tuple<int, Guid>(203, accountId1),
                 new Tuple<int, Guid>(204, accountId1),

                 new Tuple<int, Guid>(205, accountId2),
                 new Tuple<int, Guid>(206, accountId2),
                 new Tuple<int, Guid>(207, accountId3),
                 new Tuple<int, Guid>(208, accountId4),
            };

            var univCompanies = new List<UniverseCompany>();
            for(int i=0; i<universes.Count(); i++)
            {
                var univ = universes[i];
                if(i<=3)//201, 202, 203, 204
                    univCompanies.Add(new UniverseCompany() { CompanyId = cocaColaCompanyId, UniverseId = univ.Item1, AccountId = univ.Item2 });
                if(i>=4 && i<=5)//205, 206
                    univCompanies.Add(new UniverseCompany() { CompanyId = cocaColaAmatilId, UniverseId = univ.Item1, AccountId = univ.Item2 });
                if (i==6 || i==0)//201, 20207
                    univCompanies.Add(new UniverseCompany() { CompanyId = cocaColaBottlingId, UniverseId = univ.Item1, AccountId = univ.Item2 });
                if (i==7 || i==4)//208, 205
                    univCompanies.Add(new UniverseCompany() { CompanyId = cocaColaJapanId, UniverseId = univ.Item1, AccountId = univ.Item2 });
            };

            var corporateData2 = FillCorporateData2(cocaColaCompanyId, cocaColaAmatilId, cocaColaBottlingId, cocaColaJapanId,
                cocaColaCompanyCIQID, cocaColaAmatilCIQID, cocaColaBottlingCIQID, cocaColaJapanCIQID);

            var univCompaniesResult = new UniverseResearchCoverage().ProcessCoverage(univCompanies, corporateData2).ToList();
            
            Assert.AreEqual(univCompaniesResult.Count, universes.Count() * corporateData2.Count());

            List<Tuple<int, Guid>> cocaColaCompanyUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaAmatilUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaBottlingUniverses = new List<Tuple<int, Guid>>();
            List<Tuple<int, Guid>> cocaColaJapanUniverses = new List<Tuple<int, Guid>>();

            FillUniverses(cocaColaCompanyId, cocaColaAmatilId, cocaColaBottlingId, cocaColaJapanId, univCompaniesResult, 
                cocaColaCompanyCIQID, cocaColaAmatilCIQID, cocaColaBottlingCIQID, cocaColaJapanCIQID,
                cocaColaCompanyUniverses, cocaColaAmatilUniverses, cocaColaBottlingUniverses, cocaColaJapanUniverses);

            CheckUniversesForCompany(cocaColaCompanyUniverses, universes);
            CheckUniversesForCompany(cocaColaAmatilUniverses, universes);
            CheckUniversesForCompany(cocaColaBottlingUniverses, universes);
            CheckUniversesForCompany(cocaColaJapanUniverses, universes);
        }

        private static List<CorporateData> FillCorporateData2(Guid cocaColaCompanyId, Guid cocaColaAmatilId, Guid cocaColaBottlingId, Guid cocaColaJapanId,
            int cocaColaCompanyCIQID, int cocaColaAmatilCIQID, int cocaColaBottlingCIQID, int cocaColaJapanCIQID)
        {
            var cocaColaCompany = new CorporateData()
            {
                Id = cocaColaCompanyId,
                ResearchParentId = null,
                CapitalIqId = cocaColaCompanyCIQID,
                UniverseIds = new List<int>() { 104, 102, 103, 105, 108, 128, 124, 125, 126, 127, 132 }
            };

            var cocaColaAmatil = new CorporateData()
            {
                Id = cocaColaAmatilId,
                CapitalIqId = cocaColaAmatilCIQID,
                ResearchParentId = cocaColaCompanyId,
                UniverseIds = new List<int>() { 104, 199 }
            };

            var cocaColaBottling = new CorporateData()
            {
                Id = cocaColaBottlingId,
                CapitalIqId = cocaColaBottlingCIQID,
                ResearchParentId = cocaColaCompanyId,
                UniverseIds = new List<int>() { 104, 132, 122 }
            };

            var cocaColaJapan = new CorporateData()
            {
                Id = cocaColaJapanId,
                CapitalIqId = cocaColaJapanCIQID,
                ResearchParentId = cocaColaCompanyId,
                UniverseIds = new List<int>() { 104, 155, 122 }
            };

            var corporateData2 = new List<CorporateData>() { cocaColaCompany, cocaColaAmatil, cocaColaBottling, cocaColaJapan };
            return corporateData2;
        }

        private static List<CorporateData> FillCorporateData3(List<Tuple<Guid, int>> companies)
        {
            var corporateData = new List<CorporateData>();
            companies.ForEach(company =>
            {
                corporateData.Add(new CorporateData {
                    Id = company.Item1,
                    ResearchParentId = null,
                    CapitalIqId = company.Item2,
                    UniverseIds = null
                });
            });
            
            return corporateData;
        }


        private static void CheckUniversesForCompany(List<Tuple<int, Guid>> actualUniverses, List<Tuple<int, Guid>> referenceUniverses)
        {
            Assert.AreEqual(actualUniverses.Count(), referenceUniverses.Count());
            var actualUnivs = actualUniverses.OrderBy(o => o.Item1.ToString() + o.Item2.ToString()).ToList();
            var expectedUnivs = referenceUniverses.OrderBy(o => o.Item1.ToString() + o.Item2.ToString()).ToList();

            for (int i=0; i<actualUnivs.Count(); i++)
            {
                Assert.AreEqual(actualUnivs[i].Item1, expectedUnivs[i].Item1);
                Assert.AreEqual(actualUnivs[i].Item2, expectedUnivs[i].Item2);
            }
        }
    }
}
